package com.yupi.springbootinit.bizmq;

import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

/**
 * @message: 表示从队列中接收到的消息体，以字符串形式表示。
 * @channel: 表示用于与 RabbitMQ 交互的通道对象 (Channel)。通过该对象，你可以进行消息确认、拒绝等操作。
 * @deliveryTag: 表示接收到消息的交付标识 (Delivery Tag)。在手动确认消息时，你需要使用这个标识来告诉 RabbitMQ 哪条消息已经被处理。
 * @RabbitListener: SpringBootRabbitMQ注解,用于声明一个消息监听器。它指定了要监听的队列名称为 "code_queue",并且设置了手动确认消息的模式为`MANUAL`。
 * @ackMode: 用于手动确认消息。
 * @SneakyThrows: Lombok 注解，它简化了在方法中处理异常的编码。它会在代码中自动处理异常，这样你不需要显式地添加 try-catch 块来捕获异常。
 * <p>
 * 这段代码中的方法作为 RabbitMQ 的消息监听器，当从 "code_queue" 队列中接收到消息时，会打印消息内容，并手动确认消息处理。
 * 指定程序监听的消息队列和确认机制。
 * <p>
 * 使用 `ackMode = "MANUAL"` 意味着你需要显式地在消费者代码中调用 `channel.basicAck()` 来确认消息的处理，
 * 这样可以确保消息在被消费者成功处理后才被从队列中删除。如果不调用 `channel.basicAck()`，消息将会保留在队列中，直到确认处理。
 * <p>
 * 在消费者成功处理消息后，调用 `channel.basicAck()` 方法，告诉 RabbitMQ 已经处理了这条消息，并且可以将其从队列中删除。
 * `deliveryTag` 参数就是之前接收到的消息的交付标识，`false` 参数表示不批量确认（即只确认当前一条消息）。
 */
@Component
@Slf4j
public class MyMessageConsumer {
    @SneakyThrows
    @RabbitListener(queues = {"code_queue"}, ackMode = "MANUAL")
    public void receiveMessage(String message, Channel channel,
                               @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        log.info("receiveMessage message = {}", message);
        channel.basicAck(deliveryTag, false);
    }

}
